package controllers

import (
	"fmt"
	"encoding/json"
	_ "net/http"
	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
)

type Client struct {
	conn *websocket.Conn	// 用户websocket连接
	companyname string				//公司名称
}

// 1.设置为公开属性(即首字母大写)，是因为属性值私有时，外包的函数无法使用或访问该属性值(如：json.Marshal())
// 2.`json:"name"` 是为了在对该结构类型进行json编码时，自定义该属性的名称
type Message struct {
	Messagetype string	`json:"messagetype"`		// location表示定位数据，alarm表示告警数据，cancel表示取消告警数据
	Companyname string	`json:"companyname"`		//公司名称
	Longitude string	`json:"longitude"`	//经度
	Latitude string     `json:"latitude"` //维度
	Height  string      `json:"height"`    //海拔
	Clearheight string  `json:"clearheight"` //净高
	Labelid string  `json:"labelid"` //用户id
}

var (
	// 此处要设置有缓冲的通道。因为这是goroutine自己从通道中发送并接受数据。
	// 若是无缓冲的通道，该goroutine发送数据到通道后就被锁定，需要数据被接受后才能解锁，而恰恰接受数据的又只能是它自己
	join = make(chan Client, 1000)			// 用户加入通道
	leave = make(chan Client, 1000)			// 用户退出通道
	message = make(chan Message, 100000)		// 消息通道
	clients = make(map [Client] bool)		// 用户映射
)

func init() {
	fmt.Println("===========开启广播协程===========")
	go broadcaster()
}

// 广播
func broadcaster() {
	for {
		// 哪个case可以执行，则转入到该case。都不可执行，则堵塞。
		select {
		// 消息通道中有消息则执行，否则堵塞
		case msg := <-message:
			str := fmt.Sprintf("broadcaster send message to %s\n", msg.Companyname)
			fmt.Println(str)
			// 将某个用户发出的消息发送给所有用户
			for client := range clients {
				 if client.companyname == msg.Companyname || msg.Companyname == "所有公司" {
				// 将数据编码成json形式，data是[]byte类型
				// json.Marshal()只会编码结构体中公开的属性(即大写字母开头的属性)
				data, err := json.Marshal(msg)
				//fmt.Println("data:", string(data))
				if err != nil {
					beego.Error("Fail to marshal message:", err)
					return
				}
				//FileLogs.Info("发送给前端的数据", string(data)) // 转换成字符串类型便于查看
				if client.conn.WriteMessage(websocket.TextMessage, data) != nil {
					beego.Error("Fail to write message")
				}
				}
			}
		// 有用户加入加入链接
		case client := <-join:
			str := fmt.Sprintf("broadcaster-----------%s join in the chat room\n", client.companyname)
			beego.Info(str)

			clients[client] = true	// 将用户加入映射

			// 将用户加入消息放入消息通道
			var msg Message
			msg.Companyname = client.companyname
			//msg.EventType = 1
			//msg.Message = fmt.Sprintf("%s join in, there are %d preson in room", client.name, len(clients))

			// 此处要设置有缓冲的通道。因为这是goroutine自己从通道中发送并接受数据。
			// 若是无缓冲的通道，该goroutine发送数据到通道后就被锁定，需要数据被接受后才能解锁，而恰恰接受数据的又只能是它自己
			message <- msg

		// 有用户退出
		case client := <-leave:
			str := fmt.Sprintf("broadcaster-----------%s leave the chat room\n", client.companyname)
			beego.Info(str)

			// 如果该用户已经被删除
			if !clients[client] {
				//beego.Info("the client had leaved, client's name:"+client.companyname)
				break
			}

			delete(clients, client)	// 将用户从映射中删除

			// 将用户退出消息放入消息通道
			var msg Message
			msg.Companyname = client.companyname
			//msg.EventType = 2
			//msg.Message = fmt.Sprintf("%s leave, there are %d preson in room", client.name, len(clients))
			message <- msg
		}
	}
}
